#ifndef PROCESS_POOL_HPP_
#define PROCESS_POOL_HPP_

#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <string>
#include <vector>
#include <stdlib.h>
#include <cstdio>
#include<iostream>
#include"task.hpp"

#define ERR_EXIT(m)         \
    do                      \
    {                       \
        perror(m);          \
        exit(EXIT_FAILURE); \
    } while (0)

class Channel
{
public:
    Channel(pid_t subid, int wfd) : _subid(subid), _wfd(wfd)
    {
        _name = "channel-" + std::to_string(_subid) + "-" + std::to_string(_wfd);
    }
    ~Channel() {}

    void Send(int taskcode)
    {
        write(_wfd, &taskcode, sizeof(taskcode));
        std::cout<<"从"<<_wfd<<"管道写入，请进程"<<_subid<<"接收"<<std::endl;
    }
    int get_wfd()
    {
        return _wfd;
    }
private:
    pid_t _subid;
    int _wfd;
    std::string _name;
};
class ChannelManager
{
public:
    ChannelManager() : _next(0)
    {
    }

    ~ChannelManager() {}
    void Insert(pid_t subid, int wfd)
    {
        _chnnels.push_back({subid, wfd});
    }
    Channel &Select()
    {
        auto &c = _chnnels[_next];
        _next++;
        _next %= _chnnels.size();
        return c;
    }
    void Close()
    {
        for(auto e : _chnnels)
        close(e.get_wfd());
    }

private:
    std::vector<Channel> _chnnels;
    int _next;
};
class ProcessPool
{
public:
    ProcessPool(int num):_process_num(num)
    {
        _tm.Register(PrintLog);
        _tm.Register(DownLoad);
        _tm.Register(UpLoad);
    }
    ~ProcessPool()
    {
    }
    void Work(int rfd)
    {

        while (true)
        {
            int code = 0;
            ssize_t n = read(rfd, &code, sizeof(code));
            if (n > 0)
            {
                if (n != sizeof(code))
                    continue;
                std::cout<<"子进程："<<getpid()<<"收到一个任务码"<<code<<std::endl;
                _tm.Excutive(code);
                

            }
            else if (n == 0)
            {
                //printf("写端关闭，子进程退出");
                std::cout<<"写端关闭，子进程："<<getpid()<<"退出"<<std::endl;
                break;
            }
            else
            {
                printf("读取错误\n");
                break;
            }
        }
    }
    bool Start()
    {
        for(int i=0;i<_process_num;i++)
        {
        // 创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        if (n < 0)
            return false;
        // 创建子进程
        pid_t subid = fork();
        if (subid < 0)
            return false;
        else if (subid == 0)
        {
            // 子进程
            // 关闭不需要的文件描述符，1是写，0是读
            //关闭所有的写端，让父进程唯一指向写端
           int count=i+1;
           int fd=pipefd[0]+1;
           while(count--)
           close(fd++);
            //close(pipefd[1]);
             Work(pipefd[0]);
            close(pipefd[0]);
            exit(0);
        }
        else
        {
            // 父进程
            close(pipefd[0]);
            // 传输任务
            // 让channelmanager管理这个子进程和它的写文件描述符
            
            _cm.Insert(subid, pipefd[1]);
        }
    }
        return true;
    }
    void Run()
    {
        // 选择任务
        int taskcode = _tm.Code();
        // 选择信道
        auto &c = _cm.Select();
        // 发送任务
        c.Send(taskcode);
    }
    void Close()
    {
        _cm.Close();
    }

private:
    TaskManager _tm;
    ChannelManager _cm;
    
    int _process_num;
};

#endif